package org.truenewx.tnxjee.webmvc.menu;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.context.ApplicationContext;
import org.truenewx.tnxjee.core.Strings;
import org.truenewx.tnxjee.core.util.MathUtil;
import org.truenewx.tnxjee.core.util.SpringUtil;
import org.truenewx.tnxjee.core.util.StringUtil;
import org.truenewx.tnxjee.model.spec.menu.Menu;
import org.truenewx.tnxjee.model.spec.menu.MenuItem;
import org.truenewx.tnxjee.model.spec.user.security.UserConfigAuthority;

/**
 * xml格式的菜单项解析器
 *
 * @author jianglei
 */
public class MenuXmlParser implements MenuParser {

    private static final String ELEMENT_ITEM = "item";

    private final ApplicationContext context;

    public MenuXmlParser(ApplicationContext context) {
        this.context = context;
    }

    @Override
    public Menu parse(InputStream in) throws Exception {
        SAXReader reader = new SAXReader();
        Document document = reader.read(in);
        Element root = document.getRootElement();
        Menu menu = new Menu();
        menu.setName(root.attributeValue("name"));
        menu.setCaption(root.attributeValue("caption"));
        menu.setOrdinal(MathUtil.parseInt(root.attributeValue("ordinal")));
        UserConfigAuthority defaultAuthority = parseDefaultAuthority(root);
        List<MenuItem> items = parseItems(root, defaultAuthority);
        menu.setItems(items.toArray(new MenuItem[0]));
        return menu;
    }

    private UserConfigAuthority parseDefaultAuthority(Element itemElement) {
        Element defaultAuthorityElement = itemElement.element("authority");
        return parseAuthority(defaultAuthorityElement);
    }

    private UserConfigAuthority parseAuthority(Element authorityElement) {
        if (authorityElement != null) {
            String type = authorityElement.attributeValue("type");
            String rank = authorityElement.attributeValue("rank");
            String permission = authorityElement.attributeValue("permission");
            boolean intranet = Boolean.parseBoolean(authorityElement.attributeValue("intranet"));
            return new UserConfigAuthority(type, rank, permission, intranet);
        }
        return null;
    }

    private List<MenuItem> parseItems(Element parentElement, UserConfigAuthority defaultAuthority) {
        List<MenuItem> items = new ArrayList<>();
        Iterator<Element> subIterator = parentElement.elementIterator(ELEMENT_ITEM);
        while (subIterator.hasNext()) {
            MenuItem item = parseItem(subIterator.next(), defaultAuthority);
            if (item != null) {
                items.add(item);
            }
        }
        return items;
    }

    private MenuItem parseItem(Element itemElement, UserConfigAuthority defaultAuthority) {
        String caption = itemElement.attributeValue("caption");
        String profilesValue = itemElement.attributeValue("profiles");
        if (StringUtils.isNotBlank(profilesValue)) {
            String[] profiles = StringUtil.splitAndTrim(profilesValue, Strings.COMMA);
            String profile = SpringUtil.getActiveProfile(this.context);
            if (!ArrayUtils.contains(profiles, profile)) {
                return null;
            }
            // 限定运行环境的菜单项显示名称附加profile，以提醒开发者
            caption += " - " + profile;
        }
        MenuItem item = new MenuItem();
        item.setName(itemElement.attributeValue("name"));
        item.setCaption(caption);
        item.setDesc(itemElement.attributeValue("desc"));
        String editable = itemElement.attributeValue("editable");
        if (StringUtils.isNotBlank(editable)) {
            item.setEditable(Boolean.valueOf(editable));
        }
        String assignable = itemElement.attributeValue("assignable");
        if (assignable != null) {
            item.setAssignable(Boolean.valueOf(assignable));
        }

        List<UserConfigAuthority> authorities = new ArrayList<>();

        List<Element> authorityElements = itemElement.elements("authority");
        UserConfigAuthority itemDefaultAuthority = null;
        for (int i = 0; i < authorityElements.size(); i++) {
            Element authorityElement = authorityElements.get(i);
            UserConfigAuthority userConfigAuthority = parseAuthority(authorityElement);
            authorities.add(userConfigAuthority);
            if (i == 0) {
                itemDefaultAuthority = userConfigAuthority;
            }
        }
        // 已有配置权限中没有许可配置权限，则构建默认许可配置权限
        if (defaultAuthority != null && item.getPermission() == null) {
            authorities.add(new UserConfigAuthority(defaultAuthority.getType(), defaultAuthority.getRank(),
                    item.getName(), defaultAuthority.isIntranet()));
        }
        // 没有解析出任何权限，则至少添加默认权限
        if (authorities.isEmpty() && defaultAuthority != null) {
            authorities.add(defaultAuthority);
        }
        item.setAuthorities(authorities);

        // 当前节点有默认配置权限，则下级菜单的默认配置权限使用该权限
        if (itemDefaultAuthority != null) {
            defaultAuthority = itemDefaultAuthority;
        }
        // 解析下级菜单
        List<MenuItem> subs = parseItems(itemElement, defaultAuthority);
        if (!subs.isEmpty()) {
            item.setSubs(subs.toArray(new MenuItem[0]));
        }
        return item;
    }

}
